/*
 *  Copyright 2010 Wesley Gooch, Ryan Nix, Cody Wenzel.
 *  Montana State University - Spring Semester 2010
 *  Computer Science 450 - Compilers
 *  Project: Micro-Pascal Compiler
 */
package msu.compiler.semantics;

import java.util.ArrayList;
import java.util.List;
import msu.compiler.errorhandling.CompileException;
import msu.compiler.scanner.Token;

/**
 *
 * @author Wesley
 */
public class SemanticRecord {

    public static final byte FUNCTION_SYMBOL = 0;
    public static final byte PROCEDURE_SYMBOL = 1;
    public static final byte VARIABLE_SYMBOL = 2;
    public static final byte PARAMETER_SYMBOL = 3;
    public static final byte PROGRAM_SYMBOL = 4;

    public static final byte MODE_REF = 0;
    public static final byte MODE_VAL = 1;

    private Symbol symbol;
    private Token token;
    private byte kind = -1;
    private byte type = -1;
    private byte mode = -1;
    private ArrayList<SemanticRecord> parameters = new ArrayList();

    /**
     * This is essentially a mini-factory pattern that generates a symbol
     * with class attributes and returns the generated symbol.
     * 
     * @return A symbol object from class attributes.
     * @throws CompileException
     * @throws IllegalAccessException
     */
    public Symbol createSymbol() throws CompileException, IllegalAccessException {
        if (token == null || kind == -1 || type == -1) {
            throw new IllegalAccessException("Initialize Symantic Records before getSymbol!");
        } else {
            switch (kind) {
                case FUNCTION_SYMBOL:
                    symbol = new FunctionSymbol(token, type);
                    FunctionSymbol fs = (FunctionSymbol) symbol;

                    for (SemanticRecord record : parameters) {
                        record.setKind(PARAMETER_SYMBOL); //do we really need to set kind?
                        fs.addParameter((ParameterSymbol) record.createSymbol());
                    }
                    break;
                case PROCEDURE_SYMBOL:
                    symbol = new ProcedureSymbol(token, type);
                    ProcedureSymbol ps = (ProcedureSymbol) symbol;

                    for (SemanticRecord record : parameters) {
                        record.setKind(PARAMETER_SYMBOL);
                        ps.addParameter((ParameterSymbol) record.createSymbol());
                    }
                    break;
                case VARIABLE_SYMBOL:
                    symbol = new VariableSymbol(token, type);
                    break;
                case PARAMETER_SYMBOL:
                    symbol = new ParameterSymbol(token, type, mode);
                    break;
                default:
                    System.out.println("Symbol does not exist!");
                    break;
            }
        }
        return symbol;
    }

    public byte getType() {
        return type;
    }

    public Symbol getSymbol() {
        return symbol;
    }

    public void setType(byte type) {
        this.type = type;
    }

    public byte getKind() {
        return kind;
    }

    public void setKind(byte kind) {
        this.kind = kind;
    }

    public byte getMode() {
        return kind;
    }

    public void setMode(byte mode) {
        this.mode = mode;
    }

    public Token getToken() {
        return token;
    }

    public void setToken(Token token) {
        this.token = token;
    }

    public List getParameters() {
        return parameters;
    }

    public void addParameter(SemanticRecord s) {
        if (kind == FUNCTION_SYMBOL || kind == PROCEDURE_SYMBOL) {
            parameters.add(s);
        } else {
            System.out.println("ERROR STUB - SYMANTICRECORD IS NOT PARAMETER/FUNCTION");
        }
    }
}
